package com.cskaoyan.wordmemorize.common.aspect;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.SaTokenException;
import com.cskaoyan.wordmemorize.auth.StpKit;
import com.cskaoyan.wordmemorize.common.aspect.operate.OperateLog;
import com.cskaoyan.wordmemorize.common.exception.BusinessException;
import com.cskaoyan.wordmemorize.common.exception.ExcelParseException;
import com.cskaoyan.wordmemorize.common.util.JsonUtil;
import com.cskaoyan.wordmemorize.dao.entity.OperateLogDO;
import com.cskaoyan.wordmemorize.dao.mapper.OperateLogMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.cskaoyan.wordmemorize.common.aspect.operate.OperateLogConstant;

import java.lang.reflect.Method;

@Aspect
@Component
public class OperateLogAspect {
    @Autowired
    OperateLogMapper operateLogMapper;

    @Pointcut("@annotation(com.cskaoyan.wordmemorize.common.aspect.operate.OperateLog)")
    public void pointCut1() {
    }


    @Around(value = "pointCut1()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws NoSuchMethodException, JsonProcessingException {

        // // todo:先获取类中所有方法，再对比方法名确认注解在哪个方法上，再获取注解中的String dateType()和int operateType()
        // Class<?> clazz = proceedingJoinPoint.getTarget().getClass();
        // System.out.println("clazz = " + clazz);
        // String methodName = proceedingJoinPoint.getSignature().getName();
        // System.out.println("methodName = " + methodName);
        // Method[] methods = clazz.getDeclaredMethods();
        // OperateLog annotation = null;
        // for (Method method : methods) {
        //     if (method.getName().equals(methodName)) {
        //         annotation = method.getAnnotation(OperateLog.class);
        //     }
        // }
        // String dataType = annotation.dataType();
        // int operateType = annotation.operateType();
        // todo: 用MethodSignature直接获取方法上的注解
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        OperateLog annotation = method.getAnnotation(OperateLog.class);

        String dataType = annotation.dataType();
        int operateType = annotation.operateType();
        // todo:jsonStr为放入表中的data字段
        String jsonStr = null;

        // todo:status为1表示操作成功，0表示操作失败
        int status = 1;
        Object result = null;
        try {
            result = proceedingJoinPoint.proceed();
            switch (operateType) {
                case OperateLogConstant.OPERATE_ADD:
                case OperateLogConstant.OPERATE_UPDATE:
                case OperateLogConstant.OPERATE_UPDATE_STATUS:
                    jsonStr = JsonUtil.toJsonStr(proceedingJoinPoint.getArgs());
                    break;
                case OperateLogConstant.OPERATE_SINGLE_DELETE:
                case OperateLogConstant.OPERATE_BATCH_DELETE:
                case OperateLogConstant.OPERATE_EXCEL_ADD:
                    jsonStr = JsonUtil.toJsonStr(result);
                    break;
            }
        } catch (Throwable e) {

            // todo:出现异常，操作失败
            status = 0;
            exceptionConverter(e);
        } finally {
            // todo；根据dateType,operateType,status的值将操作日志存入数据库
            saveLogToDatabase(jsonStr, dataType, operateType, status);
        }

        return result;

    }

    // todo:根据原本异常类型，抛出不同异常
    public void exceptionConverter(Throwable e) {
        if (e instanceof NotLoginException) {
            throw (NotLoginException) e;
        }
        if (e instanceof NotPermissionException) {
            throw (NotPermissionException) e;
        }
        if (e instanceof SaTokenException) {
            throw (SaTokenException) e;
        }
        if (e instanceof ExcelParseException) {
            throw (ExcelParseException) e;
        }
        if (e instanceof BusinessException) {
            throw (BusinessException) e;
        }
        throw new RuntimeException();
    }


    // todo:根据dateType,operateType,status的值将操作日志存入数据库
    public void saveLogToDatabase(String data, String dataType, int operateType, int status) {
        OperateLogDO operateLogDO = new OperateLogDO();
        long employeeId = StpKit.ADMIN.getLoginIdAsLong();
        operateLogDO.setEmployeeId(employeeId);
        operateLogDO.setData(data);
        operateLogDO.setDataType(dataType);
        operateLogDO.setOperateType(operateType);
        operateLogDO.setStatus(status);
        operateLogMapper.insert(operateLogDO);
    }

}
